package genedit.model.graph;

import genedit.model.Workspace;
import genedit.view.graph.ElementPainter;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Stroke;
import java.awt.geom.Point2D;
import java.io.Serializable;
import java.util.Enumeration;
import java.util.Set;

import javax.swing.tree.TreeNode;

/**
 * Klasa zadužena za čuvanje informacije o grafičkim elementima dijagrama.
 * 
 * @author Nikola
 * @version 1.1 18/12/13
 */
public abstract class GraphElement implements Serializable, TreeNode {

	private static final long serialVersionUID = 1L;

	/**
	 * Referenca na dijagram koji sadrži element.
	 */
	protected GraphDocument parent;

	/**
	 * Veličina grafičkog elementa.
	 */
	protected Dimension size;

	/**
	 * Pozicija grafičkog elementa.
	 */
	protected Point2D position;

	/**
	 * Dubinski položaj elementa. Elementi sa manjom vrednosti ovog atributa će
	 * se iscrtavati iza elemenata sa višom vrednošću.
	 */
	protected int orderPosition;

	/**
	 * Ugao za koji je dati element zarotiran.
	 */
	protected double rotation;

	/**
	 * Ime grafičkog elementa.
	 */
	protected String name;

	/**
	 * Set konekcionih tačaka koje se nalaze u elementu.
	 */
	protected Set<ConnectionPoint> connectionPoints;

	/**
	 * Set propertia koje sadrži element.
	 */
	protected Set<Property> properties;

	/**
	 * Boja grafičkog elementa.
	 */
	protected Color color;

	/**
	 * Izgled okvira grafičkog elementa.
	 */
	protected Stroke stroke;

	/**
	 * Opis grafičkog elementa.
	 */
	protected String description;

	public GraphElement(GraphDocument parent) {
		this.parent = parent;
		this.color = new Color(0, 0, 0);
	}

	public GraphElement(GraphDocument parent, String name) {
		this.parent = parent;
		this.name = name;
		this.color = new Color(0, 0, 0);
	}

	public void setSize(Dimension newSize) {
		size = newSize;
	}

	public Dimension getSize() {
		return size;
	}

	public void setPosition(Point2D newPosition) {
		position = newPosition;
	}

	public Point2D getPosition() {
		return position;
	}

	public double getRotation() {
		return rotation;
	}

	public void setRotation(double newRotation) {
		rotation = newRotation;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Color getColor() {
		return color;
	}

	public void setColor(Color color) {
		this.color = color;
	}

	public Stroke getStroke() {
		return stroke;
	}

	public void setStroke(Stroke stroke) {
		this.stroke = stroke;
	}

	public String getDescription() {
		return description;
	}

	public void setDescription(String description) {
		this.description = description;
	}

	public void bringForward() {
		// TODO: implement
	}

	public void sendBackward() {
		// TODO: implement
	}

	public void bringToFront() {
		// TODO: implement
	}

	public void sendToBack() {
		// TODO: implement
	}

	public GraphElement(GraphElement oldGraphElement) {
		size = oldGraphElement.size;
		position = oldGraphElement.position;
		orderPosition = oldGraphElement.orderPosition;
		rotation = oldGraphElement.rotation;
	}

	public Set<ConnectionPoint> getConnectionPoints() {
		if (connectionPoints == null)
			connectionPoints = new java.util.HashSet<ConnectionPoint>();
		return connectionPoints;
	}

	public java.util.Iterator<ConnectionPoint> getIteratorConnectionPoints() {
		if (connectionPoints == null)
			connectionPoints = new java.util.HashSet<ConnectionPoint>();
		return connectionPoints.iterator();
	}

	public void setConnectionPoints(java.util.Collection<ConnectionPoint> newConnectionPoints) {
		removeAllConnectionPoints();
		for (java.util.Iterator<ConnectionPoint> iter = newConnectionPoints.iterator(); iter
				.hasNext();)
			addConnectionPoints((ConnectionPoint) iter.next());
	}

	public void addConnectionPoints(ConnectionPoint newConnectionPoint) {
		if (newConnectionPoint == null)
			return;
		if (this.connectionPoints == null)
			this.connectionPoints = new java.util.HashSet<ConnectionPoint>();
		if (!this.connectionPoints.contains(newConnectionPoint)) {
			this.connectionPoints.add(newConnectionPoint);
			newConnectionPoint.setParent(this);
		}
	}

	public void removeConnectionPoints(ConnectionPoint oldConnectionPoint) {
		if (oldConnectionPoint == null)
			return;
		if (this.connectionPoints != null)
			if (this.connectionPoints.contains(oldConnectionPoint)) {
				this.connectionPoints.remove(oldConnectionPoint);
				oldConnectionPoint.setParent(null);
			}
	}

	@Override
	public String toString() {
		return name;
	}

	public void setParent(GraphDocument parent) {
		this.parent = parent;
	}

	public void removeAllConnectionPoints() {
		if (connectionPoints != null) {
			ConnectionPoint oldConnectionPoint;
			for (java.util.Iterator<ConnectionPoint> iter = getIteratorConnectionPoints(); iter
					.hasNext();) {
				oldConnectionPoint = (ConnectionPoint) iter.next();
				iter.remove();
				oldConnectionPoint.setParent((GraphElement) null);
			}
		}
	}

	public Set<Property> getProperties() {
		if (properties == null)
			properties = new java.util.HashSet<Property>();
		return properties;
	}

	public java.util.Iterator<Property> getIteratorProperties() {
		if (properties == null)
			properties = new java.util.HashSet<Property>();
		return properties.iterator();
	}

	public void setProperties(java.util.Collection<Property> newProperties) {
		removeAllProperties();
		for (java.util.Iterator<Property> iter = newProperties.iterator(); iter.hasNext();)
			addProperties((Property) iter.next());
	}

	public void addProperties(Property newProperty) {
		if (newProperty == null)
			return;
		if (this.properties == null)
			this.properties = new java.util.HashSet<Property>();
		if (!this.properties.contains(newProperty))
			this.properties.add(newProperty);
	}

	public void removeProperties(Property oldProperty) {
		if (oldProperty == null)
			return;
		if (this.properties != null)
			if (this.properties.contains(oldProperty))
				this.properties.remove(oldProperty);
	}

	public void removeAllProperties() {
		if (properties != null)
			properties.clear();
	}

	/*
	// Metodu treba ukinuti ili barem premestiti u neku eksternu klasu koja
	// rukuje sistemom.
	public ElementPainter getPainter() {
		for (ElementPainter element : Workspace.getInstance().getActiveDocument()
				.getElementPainters()) {
			if (element.getElement().equals(this))
				return element;
		}
		return null;
	}
	*/

	@Override
	public TreeNode getChildAt(int childIndex) {
		return null;
	}

	@Override
	public int getChildCount() {
		return 0;
	}

	@Override
	public TreeNode getParent() {
		return parent;
	}

	@Override
	public int getIndex(TreeNode node) {
		return 0;
	}

	@Override
	public boolean getAllowsChildren() {
		return false;
	}

	@Override
	public boolean isLeaf() {
		return true;
	}

	@Override
	public Enumeration<?> children() {
		return null;
	}
}